//==================================================================
//  Copyright (C) 2006  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
/// @file	m5d_scene.h
///
/// M5D scene type support.
///
///
//==================================================================

#ifndef M5D_SCENE_H
#define M5D_SCENE_H

#include "m5d_types.h"
#include "m5d_model.h"
#include "m5d_material.h"
//#include "m5d_keyframe.h"
#include "m5d_mesh.h"
#include "m5d_model.h"
#include "m5d_light.h"
#include "m5d_camera.h"
#include "m5d_pntsprt.h"
#include "lightmap.h"
#include "memfile.h"

//==================================================================
namespace M5D {

//==================================================================
class Scene
{
	bool					_hint_freed_materials;
	TCHAR					_load_data_path[1024];

public:
	class Stats
	{
	public:
		int	_n_models,	_n_visible_models;
		int	_n_meshes,	_n_visible_meshes;
		int	_n_pntsprts,_n_visible_pntsprts;
	};

public:
	void					*_userdatap;
	Model					*_modelp;
	std::vector<Texture *>	_textures;
	std::vector<Material *>	_materials;
	std::vector<Model *>	_models;
	u_int					_flags;
	LightMap				_lightmap;

private:
	bool					_fog_enabled;
	PMath::Vector3			_fog_color;
	float					_fog_start;
	float					_fog_end;

	int						_flshmate_cur_model_idx;

public:
	//------------------------------------------------------------------
	Scene( const char *namep=0, const TCHAR *dirpathp=NULL );
	virtual ~Scene();

	//==================================================================
	void			SetName( const char *namep );

	Model			*GetRootModel(){ return _modelp; };

	void			UpdatePose();

	void			CalcBBox( PMath::Vector3 *box_minp, PMath::Vector3 *box_maxp );

	Mesh			*NewMesh(	 const char *namep, Model *parentp=NULL, bool serializing=false ) throw(...)
					{
						return NewMeshCopy( namep, NULL, false, parentp, serializing );
					}
	Light			*NewLight(	 const char *namep, Model *parentp=NULL, bool serializing=false ) throw(...)
					{
						return NewLightCopy( namep, NULL, parentp, serializing );
					}
	Camera			*NewCamera(	 const char *namep, Model *parentp=NULL, bool serializing=false ) throw(...)
					{
						return NewCameraCopy( namep, NULL, parentp, serializing );
					}
	PntSprt			*NewPntSprt( const char *namep, int max_verts, bool has_color, Model *parentp=NULL, bool serializing=false ) throw(...);
	DispList		*NewDispList( PackVert::Type packvert_type=PackVert::TYPE_ANY, int max_verts=0, u_int max_prim_indices=0 ) throw(...);
	DispList		*NewDispListCopy( const DispList *src_displistp ) throw(...);

	Mesh			*NewMeshCopy(	 const char *namep, Mesh	*copy_fromp, Model::CopyParams *copy_paramsp, Model *parentp=NULL, bool serializing=false ) throw(...);
	Light			*NewLightCopy(	 const char *namep, Light	*copy_fromp, Model *parentp=NULL, bool serializing=false ) throw(...);
	Camera			*NewCameraCopy(	 const char *namep, Camera	*copy_fromp, Model *parentp=NULL, bool serializing=false ) throw(...);
	PntSprt			*NewPntSprtCopy( const char *namep, PntSprt	*copy_fromp, Model *parentp=NULL, bool serializing=false ) throw(...);

	Model			*NewModel( Model::Type type, const char *namep=NULL, Model *parentp=NULL, bool serializing=false ) throw(...);
	Model			*NewModelCopy( Model *copy_fromp, Model::CopyParams *copy_paramsp=NULL, const char *namep=NULL, Model *parentp=NULL ) throw(...);
	Model			*NewModelCopyRec( Model *copy_fromp, Model::CopyParams *copy_paramsp=NULL, const char *namep=NULL, Model *parentp=NULL ) throw(...);
	Model			*FindModel( Model::Type type, const char *namep ) const;

	void			DeleteModel( Model *modelp ) {	delete modelp;	}	///< Obsolete
	void			DeleteModelRec( Model *modelp );

	void			TransformGeometryRec( Model *modelp,
										  const PMath::Matrix44 &trmat,
										  const PMath::Matrix44 *normal_mp );
	int				FindModelIdx( Model *p ) const;

	Material		*NewMaterial( const char *namep=0 ) throw(...);
	Material		*FindMaterial( const char *namep ) const;
	int				FindMaterialIdx( Material *p ) const;

	Texture			*NewTexture( const char *namep, const TCHAR *filenamep=0, PUtils::ImageBase::LoadParams *load_paramsp=NULL ) throw(...);
	Texture			*NewTexture( const char *namep, PUtils::Memfile &mf, const TCHAR *filenamep, PUtils::ImageBase::LoadParams *load_paramsp=NULL ) throw(...);
	Texture			*NewTexture( const char *namep, int w, int h, PUtils::ImageBase::BaseFormat format ) throw(...);
	Texture			*FindTexture( const char *namep ) const;
	int				FindTextureIdx( Texture *p ) const;

	void			HintFreedMaterials()	{	_hint_freed_materials = true; }

	void			EnableFog( bool onoff )							{	_fog_enabled = onoff;			}
	void			SetFogColor( float r, float g, float b )		{	_fog_color = PMath::Vector3(r,g,b);	}
	void			SetFogRange( float fog_start, float fog_end )
					{	
						_fog_start = fog_start;
						_fog_end = fog_end;
					}
	bool			IsFogEnabled() const { return _fog_enabled; }
	const PMath::Vector3	&GetFogColor() const { return _fog_color;	}
	float			GetFogStartDepth() const { return _fog_start;	}
	float			GetFogEndDepth() const	{ return _fog_end;	}

private:
	void			idleFlushUnusedMaterials();
	void			unlinkModel( Model *modelp );
	void			deleteModelRec_Siblings( Model *modelp );

	void			markTrigsUsedMaterials( Mesh *meshbp );
	void			markDispListUsedMaterials( DispList *displistp );
	void			deleteMaterial( Material *matep );
	void			unlinkTexture( Texture *texp );

	void			newModelCopyRec_Siblings( Model *src_modelp, Model::CopyParams *copy_paramsp, Model *des_parent_modelp ) throw(...);
public:
	//------------------------------------------------------------------
	int GetMaterialsN() const
	{
		return _materials.size();
	}
	//------------------------------------------------------------------
	int GetTexturesN() const
	{
		return _textures.size();
	}
	//------------------------------------------------------------------
	int GetModelsN() const
	{
		return _models.size();
	}

	//==================================================================
	int	CountTriangles() const;


	//==================================================================
	const TCHAR *GetLoadDataPath() const
	{
		return _load_data_path;
	}

	//==================================================================
	void GetStats( Stats &stats );

	//==================================================================
	Model	*PickModel( const Camera &cam, float mouse_x, float mouse_y )
	{
		
	}

private:
	void		deserializeModels( PArray<Model *> &mod_pointers, Model *user_rootp );
	void		load_rebuild_triangle_pointers( PArray<Material *> &mat_pointers );
	void		load_flag_models( bool onoff );

public:
	virtual void OnTextureCreate( Texture *mythis ){}
	virtual void OnTextureDelete( Texture *mythis ){}
	virtual void OnMaterialCreate( Material *mythis ){}
	virtual void OnMaterialDelete( Material *mythis ){}
	virtual void OnModelCreate( Model *mythis ){}
	virtual void OnModelDelete( Model *mythis ){}
	virtual void OnDispListCreate( DispList *mythis ){}
	virtual void OnDispListDelete( DispList *mythis ){}

private:
	friend class Model;
	friend class Material;
	friend class Texture;
	friend class M5DParser;
};

//==================================================================
};

#endif
